package com.bigdata.schaduler.client;

import cn.hutool.json.JSONUtil;

import java.text.MessageFormat;
import java.util.Optional;

/**
 * result
 *
 * @param <T> T
 */
public class Result<T> {
  /**
   * Status
   */
  private Integer code;

  /**
   * message
   */
  private String msg;

  /**
   * data
   */
  private T data;

  public Result() {
  }

  public Result(Integer code, String msg) {
    this.code = code;
    this.msg = msg;
  }

  private Result(Status status) {
    if (status != null) {
      this.code = status.getCode();
      this.msg = status.getMsg();
    }
  }

  public Result(Integer code, String msg, T data) {
    this.code = code;
    this.msg = msg;
    this.data = data;
  }

  /**
   * Call this function if there is success
   *
   * @param data data
   * @param <T>  type
   * @return resule
   */
  public static <T> Result<T> success(T data) {
    return new Result<>(Status.SUCCESS.getCode(), Status.SUCCESS.getMsg(), data);
  }

  public static Result success() {
    return success(null);
  }

  public boolean isSuccess() {
    return this.isStatus(Status.SUCCESS);
  }

  public boolean isFailed() {
    return !this.isSuccess();
  }

  public boolean isStatus(Status status) {
    return this.code != null && this.code.equals(status.getCode());
  }

  /**
   * Call this function if there is any error
   *
   * @param status Status
   * @return result
   */
  public static <T> Result<T> error(Status status) {
    return new Result<>(status);
  }

  /**
   * Call this function if there is any error
   *
   * @param status Status
   * @param args   args
   * @return result
   */
  public static <T> Result<T> errorWithArgs(Status status, Object... args) {
    return new Result<>(status.getCode(), MessageFormat.format(status.getMsg(), args));
  }

  public Integer getCode() {
    return code;
  }

  public void setCode(Integer code) {
    this.code = code;
  }

  public String getMsg() {
    return msg;
  }

  public void setMsg(String msg) {
    this.msg = msg;
  }

  public T getData() {
    return data;
  }

  public void setData(T data) {
    this.data = data;
  }

  @Override
  public String toString() {
    return "Status{"
        + "code='" + code
        + '\'' + ", msg='"
        + msg + '\''
        + ", data=" + data
        + '}';
  }

  public Boolean checkResult() {
    return this.code == Status.SUCCESS.getCode();
  }

  public <ResponseDataType> ResponseDataType getData(Class<ResponseDataType> responseType) {
    if (this.isSuccess()) {
      Object data = this.getData();
      return data != null
          ? JSONUtil.toBean(JSONUtil.parseObj(data), responseType, true)
          : null;
    } else {
      String msg = this.getMsg();
      Integer code = this.getCode();

      if (code != null) {
        Optional<Status> status = Status.findStatusBy(code);
        if (status.isPresent()) {
          msg = status.get().getZhMsg();
        }
      }
      throw new DolphinException("Dolphin Server Error, MSG = " + msg);
    }
  }
}